﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using CMLegado2;
using System.Configuration;
using PSE.Framework.Cryptography;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Globalization;
using PSE.Framework.Communication.Spb.Common;
using System.Timers;
using CMLegado;

namespace PSE.Framework.Communication.Spb.Client
{
    public class SpbClient
    {
        private string _sessionName;
        private string _user;
        private string _password;
        private string _host;
        private int _porta;
        private static SpbClient _client;
        private static object _locker = new object();
        private Legacy _legacy;
        private Timer _timer;
        private int _interval;

        public static SpbClient GetInstance(string sessionName)
        {
            lock (_locker)
            {
                if (_client == null)
                    _client = new SpbClient(sessionName);
            }

            return _client;
        }

        public SpbClient(string sessionName)
        {
            bool sessionFound = false;
            SpbConfigurationSection spbConfiguration = (SpbConfigurationSection)ConfigurationManager.GetSection("spbConfiguration");
            if (spbConfiguration != null)
            {
                foreach (SpbSessionConfigurationElement item in spbConfiguration.SpbSessions)
                {
                    if (item.Name == sessionName)
                    {
                        _sessionName = sessionName;
                        _user = item.User;
                        _password = item.Password;
                        _host = item.Host;
                        _porta = item.Porta;
                        _interval = item.HeartBeat;
                        sessionFound = true;
                        break;
                    }
                }

                if (!sessionFound)
                    throw new Exception(string.Format("Cannot find spb session with name '{0}' in the config file", sessionName));
            }
            else
                throw new Exception("Section spbConfiguration not found in the config file");

            this._legacy = new Legacy();
            this._timer = new Timer(_interval);
            this._timer.Elapsed += new ElapsedEventHandler(HeartBeat_Elapsed);
            this._timer.AutoReset = true;
            this._timer.Enabled = true;
        }

        void HeartBeat_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (SpbStatus.GetStatus(GetStatus()).ToLower() != "conectado")
            {
                Connect();
            }
        }


        public void Send(ref Array Mensagem, long Tamanho, ref string MsgId, ref string NUOp, string ISPB_Destinatario)
        {
            if (Mensagem == null)
                throw new ArgumentNullException("Mensagem");
            if (Tamanho < 0)
                throw new ArgumentOutOfRangeException("Tamanho");
            if (MsgId == null)
                throw new ArgumentNullException("MsgId");
            if (NUOp == null)
                throw new ArgumentNullException("NUOp");
            if (ISPB_Destinatario == null)
                throw new ArgumentNullException("ISPB_Destinatario");

            PrioridadeMensagem prioridade = new PrioridadeMensagem();
            ParameterModifier p = new ParameterModifier(6);
            p[0] = true;
            p[2] = true;
            p[3] = true;
            ParameterModifier[] mods = { p };
            object[] args = new object[] { Mensagem, Tamanho, MsgId, NUOp, ISPB_Destinatario, prioridade };
            short res = (short)this._legacy.Execute("EnviarMensagem", ref args, mods);
            SpbErrors.ErrorConstants error = (SpbErrors.ErrorConstants)res;
            if (error != SpbErrors.ErrorConstants.CM_OK)
            {
                Logger.Write(new Exception(SpbErrors.GetErrorMessage(error)));
            }
            Mensagem = (Array)args[0];
            Tamanho = (long)args[1];
            MsgId = (string)args[2];
            NUOp = (string)args[3];
            ISPB_Destinatario = (string)args[4];
            if (error != SpbErrors.ErrorConstants.CM_OK)
                throw new Exception(SpbErrors.GetErrorMessage(error));
        }

        public void HighPrioritySend(ref Array Mensagem, long Tamanho, ref string MsgId, ref string NUOp, string ISPB_Destinatario)
        {
            if (Mensagem == null)
                throw new ArgumentNullException("Mensagem");
            if (Tamanho < 0)
                throw new ArgumentOutOfRangeException("Tamanho");
            if (MsgId == null)
                throw new ArgumentNullException("MsgId");
            if (NUOp == null)
                throw new ArgumentNullException("NUOp");
            if (ISPB_Destinatario == null)
                throw new ArgumentNullException("ISPB_Destinatario");

            PrioridadeMensagem prioridade = new PrioridadeMensagem();
            prioridade = PrioridadeMensagem.CM_PRIORIDADE_ALTA;
            ParameterModifier p = new ParameterModifier(6);
            p[0] = true; p[2] = true; p[3] = true;
            ParameterModifier[] mods = { p };
            object[] args = new object[] { Mensagem, Tamanho, MsgId, NUOp, ISPB_Destinatario, prioridade };
            short res = (short)this._legacy.Execute("EnviarMensagem", ref args, mods);
            SpbErrors.ErrorConstants error = (SpbErrors.ErrorConstants)this._legacy.Execute("EnviarMensagemStr", ref args, mods);
            if (error != SpbErrors.ErrorConstants.CM_OK)
            {
                Logger.Write(new Exception(SpbErrors.GetErrorMessage(error)));
            }
            if (error != SpbErrors.ErrorConstants.CM_OK)
                throw new Exception(SpbErrors.GetErrorMessage(error));
        }

        public Array Receive(
                            ref int Retorno,
                            ref int Tamanho,
                            ref string Data,
                            ref string Hora,
                            ref string MSG_ID,
                            ref string NUOp,
                            ref string CodMsg,
                            ref string ISPB_Emissor)
        {
            if (Data == null)
                throw new ArgumentNullException("Data");
            if (Hora == null)
                throw new ArgumentNullException("Hora");
            if (MSG_ID == null)
                throw new ArgumentNullException("MSG_ID");
            if (NUOp == null)
                throw new ArgumentNullException("NUOp");
            if (Hora == null)
                throw new ArgumentNullException("CodMsg");
            if (MSG_ID == null)
                throw new ArgumentNullException("ISPB_Emissor");

            ParameterModifier p = new ParameterModifier(8);
            p[0] = true; p[1] = true; p[2] = true; p[3] = true; p[4] = true; p[5] = true; p[6] = true; p[7] = true;
            ParameterModifier[] mods = { p };
            object[] args = new object[] { Retorno, Tamanho, Data, Hora, MSG_ID, NUOp, CodMsg, ISPB_Emissor };
            Array res = (Array)this._legacy.Execute("BuscaMensagem", ref args, mods);
            Retorno = (int)args[0];
            Tamanho = (int)args[1];
            Data = (string)args[2];
            Hora = (string)args[3];
            MSG_ID = (string)args[4];
            NUOp = (string)args[5];
            CodMsg = (string)args[6];
            ISPB_Emissor = (string)args[7];
            return res;
        }

        public Array ReceiveEx(
                            ref int Retorno,
                            ref int Tamanho,
                            ref string Data,
                            ref string Hora,
                            ref string MQ_ID,
                            ref string MSG_ID,
                            ref string NUOp,
                            ref string CodMsg,
                            ref string ISPB_Emissor)
        {
            if (Data == null)
                throw new ArgumentNullException("Data");
            if (Hora == null)
                throw new ArgumentNullException("Hora");
            if (MQ_ID == null)
                throw new ArgumentNullException("MSG_ID");
            if (MSG_ID == null)
                throw new ArgumentNullException("MSG_ID");
            if (NUOp == null)
                throw new ArgumentNullException("NUOp");
            if (Hora == null)
                throw new ArgumentNullException("CodMsg");
            if (MSG_ID == null)
                throw new ArgumentNullException("ISPB_Emissor");

            ParameterModifier p = new ParameterModifier(9);
            p[0] = true; p[1] = true; p[2] = true; p[3] = true; p[4] = true; p[5] = true; p[6] = true; p[7] = true; p[8] = true;
            ParameterModifier[] mods = { p };
            object[] args = new object[] { Retorno, Tamanho, Data, Hora, MQ_ID, MSG_ID, NUOp, CodMsg, ISPB_Emissor };
            Array res = (Array)this._legacy.Execute("BuscaMensagemEx", ref args, mods);
            Retorno = (int)args[0];
            Tamanho = (int)args[1];
            Data = (string)args[2];
            Hora = (string)args[3];
            MQ_ID = (string)args[4];
            MSG_ID = (string)args[5];
            NUOp = (string)args[6];
            CodMsg = (string)args[7];
            ISPB_Emissor = (string)args[8];
            return res;
        }

        public int MessageCount()
        {
            int quantidade = 0;
            ParameterModifier p = new ParameterModifier(1);
            p[0] = true;
            ParameterModifier[] mods = { p };
            object[] args = new object[] { quantidade };
            short res = (short)this._legacy.Execute("MensagensNaFila", ref args, mods);
            SpbErrors.ErrorConstants error = (SpbErrors.ErrorConstants)res;
            if (error != SpbErrors.ErrorConstants.CM_OK)
            {
                Logger.Write(new Exception(SpbErrors.GetErrorMessage(error)));
            }
            quantidade = (int)args[0];
            return quantidade;
        }

        public SpbStatus.Status Connect()
        {
            bool persistente = false;
            string pwd = RijndaelCryptographer.DecryptString(_password);
            object[] args = new object[] { persistente, _user, pwd, _host, _porta };
            short res = (short)this._legacy.Execute("Conectar", args);
            SpbStatus.Status error = (SpbStatus.Status)res;
            return (error);
        }

        public void Disconnect()
        {
            object[] args = new object[] { };
            this._legacy.Execute("Desconectar", args);
        }

        public SpbStatus.Status GetStatus()
        {
            object[] args = new object[] { };
            short res = (short)this._legacy.Execute("Status", args);
            SpbStatus.Status error = (SpbStatus.Status)res;
            return (error);
        }

        public void RemoveMessage(string MsgID)
        {
            object[] args = new object[] { MsgID };
            short res = (short)this._legacy.Execute("RemoverMensagem", args);
            SpbErrors.ErrorConstants error = (SpbErrors.ErrorConstants)res;
            if (error != SpbErrors.ErrorConstants.CM_OK)
                throw new Exception(SpbErrors.GetErrorMessage(error));
        }

    }
}
